package com.iambookmaster.client.remote;
import java.util.HashMap;
import java.util.Iterator;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.Hidden;
import com.google.gwt.user.client.ui.NamedFrame;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.iambookmaster.client.common.Base64Coder;
import com.iambookmaster.client.common.JSONParser;
import com.iambookmaster.client.locale.AppConstants;
import com.iambookmaster.client.locale.AppLocale;
public class RemotePanel extends VerticalPanel {
public static final String CODE_REDIRECT = "redirect";
public static final String CODE_SUCCESS = "success";
public static final String CODE_ERROR = "error";
public static final String CODE_LOAD = "load";
public static final String FIELD_ANSWER_CODE = "c";
public static final String FIELD_URL = "u";
public static final String FIELD_CALLBACK = "c";
public static final String FIELD_ERROR_SHORT = "e";
public static final String FIELD_DESCRIPTION = "d";
public static final String FIELD_WAIT = "w";
private static int COUNTER;
private static final AppConstants appConstants = AppLocale.getAppConstants();
// private static final String GO_BACK = GWT.getHostPageBaseURL()+appConstants.remoteBackPage();
private static final String PROCESS = GWT.getHostPageBaseURL()+appConstants.remoteProgressPage();
// private static final String CALLBACK = GWT.getHostPageBaseURL()+appConstants.remoteSuccessPage();
private static String CALLBACK;
private static String CALLBACK_BASE64;
public static final String LOCALE_IN_REQUEST = "locale";
private Timer timeoutChecher;
private RemotePanelListener listener;
private String serverUrl;
public String getServerUrl() {
return serverUrl;
}
public void setServerUrl(String serverUrl) {
this.serverUrl = serverUrl;
}
private RemoteRequest currentRequest;
private NamedFrame frame;
private FormPanel form;
private FlowPanel formElements;
private String framName;
private HashMap<String,String> urlMapping = new HashMap<String, String>(5);
public RemotePanel(String serverUrl,RemotePanelListener listener) {
this.listener = listener;
this.serverUrl = serverUrl;
CALLBACK = GWT.getHostPageBaseURL()+appConstants.remoteProgressPage();
if (CALLBACK.startsWith("file:///")) {
CALLBACK = CALLBACK.replace("file://", "file://///");
}
CALLBACK_BASE64 = Base64Coder.encodeString(CALLBACK);
setSize("100%", "100%");
framName = "RemotePanel"+String.valueOf(++COUNTER);
frame = new NamedFrame(framName);
frame.setUrl(CALLBACK);
frame.setSize("100%", "100%");
add(frame);
setCellHeight(frame, "100%");
setCellWidth(frame, "100%");
form = new FormPanel(frame);
form.setVisible(false);
add(form);
setCellHeight(form, "1px");
setCellWidth(form, "100%");
formElements = new FlowPanel();
form.add(formElements);
}
public void refresh() {
perform(currentRequest);
}
private Command perfomCommand = new Command() {
public void execute() {
setFrameWindowName(frame.getElement(), framName);
formElements.clear();
form.setAction(currentRequest.getUrl());
form.setMethod(currentRequest.isPost() ? FormPanel.METHOD_POST : FormPanel.METHOD_GET);
form.setEncoding(FormPanel.ENCODING_URLENCODED);
final HashMap<String,String> params = currentRequest.getParameters();
if (params != null && params.size()>0) {
addParameters(params,CALLBACK_BASE64);
} else {
addParameter(FIELD_CALLBACK,CALLBACK_BASE64);
}
if (currentRequest.isWaitForAnswer()) {
//wait for answer
timeoutChecher = new Timer() {
@Override
public void run() {
String name;
try {
name = getFrameWindowName(frame.getElement());
if (framName.equals(name)) {
//nothing
} else if (name.length()>0) {
//found
timeoutChecher.cancel();
parseAnswer(name);
}
} catch (Throwable e) {
}
}
};
timeoutChecher.scheduleRepeating(300);
} else {
listener.success();
}
form.submit();
}
};
public void perform(RemoteRequest request) {
if (timeoutChecher != null) {
timeoutChecher.cancel();
}
listener.beforeRequest();
currentRequest = request;
if (request.getUrl() == null) {
if (urlMapping.containsKey(request.getFunction())) {
request.setUrl(urlMapping.get(request.getFunction()));
} else {
request.setUrl(serverUrl+request.getFunction());
}
}
frame.setUrl(PROCESS);
new Timer() {
public void run() {
//wait for our local page is loaded
String name = getFrameWindowName(frame.getElement());
if (name.length()>0) {
cancel();
DeferredCommand.addCommand(perfomCommand);
}
}
}.scheduleRepeating(300);
}
private void parseAnswer(String answer) {
// Window.prompt("Answer", answer);
listener.serverReplied(answer);
JavaScriptObject source;
String code;
String url;
JSONParser parser = JSONParser.getInstance();
try {
String base = Base64Coder.decodeString(answer);
source = JSONParser.eval(base);
code = parser.propertyString(source, FIELD_ANSWER_CODE);
url = parser.propertyNoCheckString(source, FIELD_URL);
} catch (Exception e) {
//wrong
listener.error(answer);
return;
}
if (CODE_REDIRECT.equals(code)) {
currentRequest.setUrl(url);
//remember redirect for future
urlMapping.put(currentRequest.getFunction(), url);
refresh();
} else if (CODE_SUCCESS.equals(code)) {
listener.success();
if (url == null) {
frame.setUrl(CALLBACK);
printFullDescription(source);
} else {
frame.setUrl(PROCESS);
final String callUrl = url;
DeferredCommand.addCommand(new Command(){
public void execute() {
frame.setUrl(callUrl);
}
});
}
} else if (CODE_LOAD.equals(code)) {
if (url == null) {
frame.setUrl(CALLBACK);
listener.error(AppLocale.getAppConstants().remoteCannotLoadModel());
} else {
listener.load(url);
frame.setUrl(PROCESS);
}
} else if (CODE_ERROR.equals(code)) {
listener.error(code);
printFullDescription(source);
} else {
//other code - error
listener.error(JSONParser.getInstance().propertyNoCheckString(source, FIELD_ERROR_SHORT));
if (url == null) {
frame.setUrl(CALLBACK);
printFullDescription(source);
} else {
frame.setUrl(url);
}
}
}
private void printFullDescription(JavaScriptObject source) {
final String fullDescription = JSONParser.getInstance().propertyNoCheckString(source, FIELD_DESCRIPTION);
if (fullDescription != null) {
new Timer() {
public void run() {
if (printFullDescription(frame.getElement(),fullDescription)) {
cancel();
}
}
}.schedule(500);
}
}
private native String getFrameWindowName(Element frame) /*-{
try {
var doc = (frame.contentWindow || frame.contentDocument);
return doc.window.name;
} catch (e) {
return '';
}}-*/;
private native boolean printFullDescription(Element frame,String text) /*-{
try {
var doc = (frame.contentWindow || frame.contentDocument);
if (doc.document) {
doc = doc.document;
}
doc.body.innerHTML=text;
return true;
} catch (e) {
return false;
}
}-*/;
// private native JavaScriptObject getFrameDocument(Element frame) /*-{
// var doc = (frame.contentWindow || frame.contentDocument);
// if (doc.document) {
// doc = doc.document;
// }
// return doc;
// }-*/;
private native void setFrameWindowName(Element frame,String name) /*-{
try {
var doc = (frame.contentWindow || frame.contentDocument);
doc.window.name = name;
} catch (e) {
}
}-*/;
protected void addParameters(HashMap<String, String> params, String callback) {
for (Iterator<String> iterator = params.keySet().iterator(); iterator.hasNext();) {
String name = iterator.next();
addParameter(name,params.get(name));
}
addParameter(FIELD_CALLBACK,callback);
}
private void addParameter(String name, String value) {
Hidden hidden = new Hidden(name);
hidden.setValue(value);
formElements.add(hidden);
}
public void done() {
frame.setUrl(CALLBACK);
}
}